﻿using Io.Elegant;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using System.Diagnostics;
using System.Text;

namespace Elio.Sessions;

public abstract class AbstractSession
{
    protected abstract string? SessionName { get; set; }
    protected abstract IClientStreamWriter<Interaction>? ReqStream { get; set; }
    protected abstract IAsyncStreamReader<Interaction>? RespStream { get; set; }

    protected abstract Task OnCreate(long sid = 0, long fid = 0, params Any[] argv);
    protected abstract Task OnReceive(string name, long sessionId, long futureId, params Any[] argv);
    protected abstract Task Create(long sid, long fid, params Any[] argv);
    protected abstract Task OnDestroy();
    protected abstract Task OnError();

    protected virtual async Task Destroy() =>
        //Debug.WriteLine($"###[MainDS] {SessionName} ReqStream Complete");
        await ReqStream!.CompleteAsync();

    protected async Task ReceiveMessage()
    {
        await foreach (Interaction msg in RespStream!.ReadAllAsync())
        {
            (string name, long sid, long fid) = (msg.Name, msg.Session, msg.Future);
            Any[] argv = msg.Argv.ToArray();

            await MainThread.InvokeOnMainThreadAsync(async () =>
                await OnReceive(name, sid, fid, argv));

#if DEBUG
            Debug.WriteLine($"###[MainRM] {SessionName} Recv {name} {GetArgInfo(argv)}");
#endif
        }
    }

    protected async Task Send(Interaction req)
    {
        await ReqStream!.WriteAsync(req);

#if DEBUG
        //ParseAny(out object[] argv, req.Argv.ToArray());
        Debug.WriteLine($"###[MainSM] {SessionName} Send {req.Name} {GetArgInfo(req.Argv.ToArray())}");
#endif
    }

    private static void ParseAny(out object[] objects, Any[] argv)
    {
        int len = argv.Length;
        objects = new object[len];
        for (int i = 0; i < len; i++)
        {
            if (argv[i].TryUnpack(out StringValue res1))
            {
                objects[i] = res1.Value;
            }
            else if (argv[i].TryUnpack(out Int32Value res2))
            {
                objects[i] = res2.Value;
            }
            else if (argv[i].TryUnpack(out Int64Value res3))
            {
                objects[i] = res3.Value;
            }
            else if (argv[i].TryUnpack(out FloatValue res4))
            {
                objects[i] = res4.Value;
            }
            else if (argv[i].TryUnpack(out BoolValue res5))
            {
                objects[i] = res5.Value;
            }
            else if (argv[i].TryUnpack<Interaction>(out Interaction? res6))
            {
                objects[i] = res6;
            }
        }
    }

    private static string GetArgInfo(params Any[] argv)
    {
        ParseAny(out object[] objects, argv);
        StringBuilder res = new();
        // 详细信息
        objects
            .ToList()
            .ForEach(o => res.Append(o + " "));
        // 简略信息
        //if (argv.Length == 0) return string.Empty;
        //if (argv[0] is string str) res.Append(str);
        //else if (argv[0] is int n) res.Append(n.ToString());
        //else if (argv[0] is long l) res.Append(l.ToString());
        //else if (argv[0] is bool b) res.Append(b.ToString());
        return res.ToString();
    }
}